package com.biglead.demo.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.biglead.demo.common.R;
import com.biglead.demo.config.SnowFlakeCompone;
import com.biglead.demo.mapper.OrderMapper;
import com.biglead.demo.pojo.*;
import com.biglead.demo.rabbit.order.delay.OrderDelayedMQSender;
import com.biglead.demo.rabbit.order.common.OrderMQSender;
import com.biglead.demo.service.GoodsService;
import com.biglead.demo.service.OrderService;
import com.biglead.demo.service.SecKillGoodsService;
import com.biglead.demo.service.SecKillOrderService;
import com.biglead.demo.utils.JsonUtils;
import com.biglead.demo.vo.GoodsVo;
import com.biglead.demo.vo.OrderVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class OrderServiceImpl implements OrderService, InitializingBean {
    @Autowired
    private SecKillGoodsService secKillGoodsService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private GoodsService goodsService;

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private SecKillOrderService secKillOrderService;
    @Autowired
    OrderDelayedMQSender orderDelayedMQSender;
    @Override
    @Transactional // 一个事务
    public R toSecKill(Long goodsId, Long userId, Long sn) {
        // 秒杀商品表库存减一
        SeckillGoods seckillGoods = secKillGoodsService.findByGoodsId(goodsId);
        seckillGoods.setStockCount(seckillGoods.getStockCount() - 1);
        // 库存超卖
        int update = secKillGoodsService.updateStockCount(seckillGoods);
        if (update < 1) {
            //更新redis订单状态
            redisTemplate.opsForValue().set("sn:" + sn, "秒杀失败 重复抢购", 1, TimeUnit.DAYS);
            log.error("商品库存更新失败 商品库存不足");
            // 更新失败
            return R.error("商品库存不足");
        }
        Goods goods = goodsService.findGoods(goodsId);

        if (seckillGoods.getStockCount() < 1) {
            // 设置该商品库存为空
            redisTemplate.opsForValue().set("isStockEmpty:" + goods.getId(), "0");
            //更新redis订单状态  //更新redis订单状态  一天的过期时间
            redisTemplate.opsForValue().set("sn:" + sn, "秒杀失败 商品库存不足", 1, TimeUnit.DAYS);
            return R.error("商品库存不足");
        }


        // 下订单
        Order order = new Order();
        order.setUserId(userId);
        order.setGoodsId(goodsId);
        order.setDeliveryAddrId(0L);
        order.setGoodsName(goods.getGoodsName());
        order.setGoodsCount(1);
        order.setGoodsPrice(seckillGoods.getSeckillPrice());
        order.setOrderChannel(1);
        order.setStatus(0); // 订单创建中
        order.setCreateDate(new Date());
        order.setSn(sn);
        orderMapper.insert(order);

        // 生成秒杀订单
        SeckillOrder seckillOrder = new SeckillOrder();
        seckillOrder.setUserId(userId);
        seckillOrder.setOrderId(order.getId());
        seckillOrder.setGoodsId(goods.getId());
        seckillOrder.setSn(sn);
        secKillOrderService.save(seckillOrder);

        //缓存秒杀订单
        redisTemplate.opsForValue().set("order:" + userId + ":" + goodsId, seckillOrder);
        //更新redis订单状态  一天的过期时间
        redisTemplate.opsForValue().set("sn:" + sn, "ok", 1, TimeUnit.DAYS);
        //发送超时取消订单
        //保存数据到ES中
        OrderMessage message = new OrderMessage(userId, order.getId());
        //发送一个延迟消息，如果超时未支付，则取消订单 10 分钟
        orderDelayedMQSender.sendOrderDelayMessage(JsonUtils.toJson(message),10*60*1000);

        return R.okData(order);
    }

    @Override
    public OrderVo detailFromId(Long orderId) {
        if (orderId == null) {
            throw new RuntimeException("订单不存在");
        }
        Order order = orderMapper.selectById(orderId);
        if (Objects.isNull(order)) {
            // 订单不存在
            throw new RuntimeException("订单不存在");
        }
        GoodsVo goodsVo = goodsService.findGoodsVoByGoodsId(order.getGoodsId());

        OrderVo orderVo = new OrderVo();
        orderVo.setOrder(order);
        orderVo.setGoodsVo(goodsVo);
        return orderVo;
    }

    @Override
    public OrderVo detailFromSn(Long sn) {
        if (sn == null) {
            throw new RuntimeException("订单不存在");
        }
        Order order = orderMapper.selectOne(new QueryWrapper<Order>().eq("sn", sn));
        if (Objects.isNull(order)) {
            // 订单不存在
            throw new RuntimeException("订单不存在");
        }
        GoodsVo goodsVo = goodsService.findGoodsVoByGoodsId(order.getGoodsId());

        OrderVo orderVo = new OrderVo();
        orderVo.setOrder(order);
        orderVo.setGoodsVo(goodsVo);
        return orderVo;
    }

    @Override
    public Order getOrderDetail(Long orderId) {
        if (orderId == null) {
            throw new RuntimeException("订单不存在");
        }
        Order order = orderMapper.selectById(orderId);
        if (Objects.isNull(order)) {
            // 订单不存在
            throw new RuntimeException("订单不存在");
        }
        return order;
    }

    @Override
    public void updateOrderById(Order order) {
        orderMapper.updateById(order);
    }

    @Autowired
    SnowFlakeCompone snowFlakeCompone;
    @Autowired
    private OrderMQSender mqSender;

    @Override
    public R createPreOrder(Long goodsId, Long userId) {
        log.info("预下单处理 userId:{} goodsId:{} ", userId, goodsId);

        //获取redis中的商品库存 先判断商品是否有库存
        Boolean aBoolean = redisTemplate.hasKey("goodStock:" + goodsId);

        if (Boolean.FALSE.equals(aBoolean)) {
            return R.error("下单失败 商品库存不足");
        }
        //Redis 缓存获取商品库存
        int goodsStock = Integer.valueOf(redisTemplate.opsForValue().get("goodStock:" + goodsId).toString());

        if (goodsStock == 0) {
            return R.error("下单失败 商品库存不足");
        }
        //生成订单号
        long sn = snowFlakeCompone.getInstance().nextId();
        //保存到redis中 状态 doing 正在处理中 //过期时间30分钟
        redisTemplate.opsForValue().set("sn:" + sn, "doing",30, TimeUnit.MINUTES);
        //发送下单消息
        SecKillMessage message = new SecKillMessage(userId, goodsId, sn);
        mqSender.sendCommonOrderMessage(JsonUtils.toJson(message));
        //把商品订单号返回到前端
        return R.okData(sn);
    }

    @Override
    @Transactional
    public R createOrder(Long goodsId, Long userId, Long sn) {

        log.info("下单处理 userId:{} goodsId:{} ", userId, goodsId);
        int goodsStock = Integer.valueOf(redisTemplate.opsForValue().get("goodStock:" + goodsId).toString());

        if (goodsStock == 0) {
            //更新redis订单状态
            redisTemplate.opsForValue().set("sn:" + sn, "下单失败 库存不足", 1, TimeUnit.HOURS);//过期时间1小时
            log.info("下单失败 redis 商品库存不足");
            return R.error("商品库存不足");
        }
        //查询商品详情
        Goods goods = goodsService.findGoods(goodsId);
        //商品的实际库存
        if (goods.getGoodsStock() < 1) {
            redisTemplate.opsForValue().set("sn:" + sn, "下单失败 库存不足", 1, TimeUnit.HOURS);//过期时间1小时
            // 设置该商品库存为空
            redisTemplate.opsForValue().set("goodStock:" + goods.getId(), "0");
            log.info("库存不足 数据库 下单失败");
            return R.error("商品库存不足");
        }
        //减库存
        int currentStock = goods.getGoodsStock() - 1;
        //更新数据库 库存
        goods.setGoodsStock(currentStock);
        int update = goodsService.updateGoodsStock(goods);
        if (update <= 0) {
            redisTemplate.opsForValue().set("sn:" + sn, "下单失败 库存不足", 1, TimeUnit.HOURS);//过期时间1小时
            log.info("更新库存失败 下单失败");
            return R.error("商品库存不足");
        }

        //更新redis 缓存
        redisTemplate.opsForValue().decrement("goodStock:" + goods.getId());
        // 下订单
        Order order = new Order();
        order.setUserId(userId);
        order.setGoodsId(goodsId);
        order.setDeliveryAddrId(0L);
        order.setGoodsName(goods.getGoodsName());
        order.setGoodsCount(1);
        order.setGoodsPrice(goods.getGoodsPrice());
        order.setOrderChannel(1);
        order.setStatus(0); // 订单创建中
        order.setCreateDate(new Date());
        order.setSn(sn);
        orderMapper.insert(order);
        log.info("下单成功 userId:{} goodsId:{} orderId:{} sn:{}", userId, goodsId, order.getId(), sn);
        //缓存普通订单
        redisTemplate.opsForValue().set("order:" + userId + ":" + goodsId, order);
        //更新订单号状态
        redisTemplate.opsForValue().set("sn:" + sn, "ok");
        //保存数据到ES中
        OrderMessage message = new OrderMessage(userId, order.getId());

        //发送一个延迟消息，如果超时未支付，则取消订单 10 分钟
        orderDelayedMQSender.sendOrderDelayMessage(JsonUtils.toJson(message),10*60*1000);

        //后续实现
        return R.okData(order);
    }

    /**
     * 初始化商品数量到 redis 中
     * 当然这个是本地测试使用的
     *
     * @return
     */
    @Override
    public R startOrderInit() {
        List<Goods> goods = goodsService.findAllGoods();
        if (CollectionUtils.isEmpty(goods)) {
            return R.error("无秒杀商品");
        }

        goods.forEach(g -> {
            log.info("初始化商品库存 goodsId:{} stock: {}", g.getId(), g.getGoodsStock());
            redisTemplate.opsForValue().set("goodStock:" + g.getId(), g.getGoodsStock());
        });
        return R.ok("初始化商品库存完成");
    }


    @Override
    public void afterPropertiesSet() throws Exception {
        this.startOrderInit();
    }
}
